select模块主要是用于IO多路复用

select 提供了三个方法: 

  • select -> window 仅支持select
  • poll -> linux可用
  • eopll -> linux可用

1. .select()方法

  • 三个必传的参数:
    • 输入列表 -> 就是IO 中的 I -> 监听输入列表中的内容是否有用户进行了连接(是否有数据返回),一般是监听 sk 和 conn
    • 输出列表 -> 就是IO 中的 O
    • 错误列表

  • .select()方法的返回值是一个元组,元组中包含了输入列表(包含 以被用户连接的sk 或 多个得到数据的conn对象)、输出列表、错误列表

  • 使用select实现IO多路复用

# server.py

import socket
import select

sk = socket.socket()
sk.bind(('127.0.0.1', 8080))
sk.listen()

read_lst = [sk]  # 输入列表
while True:
    rl, wl, xl = select.select(read_lst, [], [])  # 监听输入列表中sk或多个conn是否有用户进行连接(是否有数据返回),如果有就会返回一个列表中包含 以被用户连接的sk 或 多个得到数据的conn对象 (因为有多个客户端对服务端进行连接,所以才会有多个conn对象)
    for item in rl:  # 循环select的返回值中的输入列表,因为里面包含了 以被用户连接的sk 或 多个得到数据的conn对象(因为有多个客户端对服务端进行连接,所以才会有多个conn对象)
        if item == sk:  # 判断是否是sk对象(因为sk对象只会有一个,并且是同一个),如果等于sk对象那么就代表有新的客户端对服务端进行连接
            conn, addr = item.accept()  # 得到一个conn客户端对象
            read_lst.append(conn)  # 将 与服务端进行链接了的客户端对象放入 read_lst 输入列表中
        else:  # 如果不是sk对象就是conn对象
            ret = item.recv(1024).decode('utf-8')
            if not ret:  # 判断接收到的消息是否为空,如果是就说明客户端已经断开连接这样就关闭该客户端并且从read_lst输入列表中删除,如果不为空就打印该数据并且向客户端回一条消息
                item.close()
                read_lst.remove(item)
            else:
                print(ret)
                item.send(ret.upper().encode('utf-8'))

# client.py

import socket
import time
from threading import Thread


def fun():
    sk = socket.socket()
    sk.connect(('127.0.0.1', 8080))
    for i in range(10):
        time.sleep(2)
        sk.send(b'hello')
        print(sk.recv(1024))
    sk.close()


for i in range(10):
    Thread(target=fun).start()